#include "an.client.h"
#include "an.rpc.h"

#include "../Headers/config.h"
#include "../Headers/types.h"
#include "../Headers/log.h"

#include "../NS/nameserver.h"

#include <string>
#include <cstring>

TOB::AN::Client::Client(TOB::Nameserver::IP nsip, std::string username, std::string password) : TOB::AuthRequired(nsip, username, password) {
  std::string NSHost;
  TOB::Nameserver::convertIP(nsip, NSHost);
  
  TOB::Nameserver ns = TOB::Nameserver(NSHost);
  nsconnected = (ns.requestAddress(Server::Authentication, ANIP) == Code::Okay);
  ns.convertIP(ANIP, ANHost);
  
  if (!nsconnected) {
    connected = false;
  }
  else {
    memcpy(user.username, username.c_str(), username.length() + 1); // !!!
    memcpy(user.password, password.c_str(), password.length() + 1); // !!!
    user.nsip = static_cast<int>(nsip);
    
    // connect to server
    clnt = clnt_create(ANHost.c_str(), AN_PROG, AN_VERSION, "udp");
    connected = true;
    if (clnt == NULL) {
      connected = false;
    }
  }
}

TOB::AN::Client::~Client() {
  if (clnt != NULL && connected) {
    clnt_destroy(clnt);
  }
}

Code::Type TOB::AN::Client::login() {
  if (!nsconnected) { return Code::NS_DoesntRespond; }
  if (!connected) { return Code::AN_DoesntRespond; }
  int* respond;
  respond = login_1(&user, clnt);
  if (!respond) { return Code::AN_DoesntRespond; }
  return static_cast<Code::Type>(*respond);
}

Code::Type TOB::AN::Client::logout() {
  if (!nsconnected) { return Code::NS_DoesntRespond; }
  if (!connected) { return Code::AN_DoesntRespond; }
  int* respond;
  respond = logout_1(&user, clnt);
  if (!respond) { return Code::AN_DoesntRespond; }
  return static_cast<Code::Type>(*respond);
}

Code::Type TOB::AN::Client::online(bool& result) {
  if (!nsconnected) { return Code::NS_DoesntRespond; }
  if (!connected) { return Code::AN_DoesntRespond; }
  int* respond;
  respond = online_1(&user, clnt);
  if (!respond) { return Code::AN_DoesntRespond; }
  if (*respond == static_cast<int>(Code::Okay)) {
    result = true;
    return Code::Okay;
  }
  result = false;
  return static_cast<Code::Type>(*respond);
}

bool TOB::AN::Client::isConnected() {
  return connected;
}
